/*
 * This file is part of Space Invaders: Rehash
 * Copyright (C)2007 Vicent Marti (tanoku@gmail.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>

#include "SDL.h"
#include "SDL_ttf.h"
#include "SDL_opengl.h"

#include "game.h"
#include "main.h"
#include "gfx.h"
#include "font_handler.h"
#include "sprites.h"
#include "game_const.h"

Player::Player( Game *parent )
{
	m_x = SCREEN_W/2;
	m_y = SCREEN_H - PLAYER_H/2 - 32;
	m_vel = 0;
	m_missileCount = 0;
	m_lastShoot = SDL_GetTicks();
	m_parent = (Game*)parent;
	m_health = 100;
}

void Player::getBounds( SDL_Rect *r )
{
	r->x = m_x - PLAYER_BB_W;
	r->y = m_y - PLAYER_BB_H;
	r->w = PLAYER_BB_W*2;
	r->h = (int)(PLAYER_BB_H*1.5f);
}

void Player::hit( int damage )
{
	if ( isDead() )
		return;
		
	if (m_parent->getGameRules() & GR_GODMODE)
		return;

	m_health -= damage;

	if ( isDead() )
	{
		Mix_PlayChannel( -1, g_Sounds[SOUND_PLAYERDEAD], 0 );
		m_deathFXTimer.start();
	}
}

void Player::render()
{        
	float x,y,z;
	glScreenToWorld( m_x, m_y, x, y, z );
	
// TODO: either replace the model of the damn canon or make a sarcastic remark somewhere
// in the code regarding my absolute lack of skill when it comes to 3D modeling
// and texturing...
	glDrawModel( g_Models[0], x, y+0.03f, z, g_Textures[5], 1.0f, 1.0f, 1.0f, 0.015f, 0.0f, 0.0, 0.0f, 0.0f );
}

void Player::tick()
{
	if ( !isDead() && (m_parent->getGameRules() & GR_BOSSFIGHT_1) == 0 && 
	     m_parent->getStatus() == STATUS_PLAYING )
	{
// FIXME: how is this acceleration code looking?
// maybe a tad too jumpy? I dunno, it's giving me a headache
		if ( g_Keys[KLEFT] )
		{
			m_vel -= 1;
			
			if ( m_vel < -PLAYER_W/4 )
				m_vel = -PLAYER_W/4;
		}
		
		if ( g_Keys[KRIGHT] )
		{
			m_vel += 1;
			
			if ( m_vel > PLAYER_W/4 )
				m_vel = PLAYER_W/4;
		}
		
		if ( !g_Keys[KRIGHT] && !g_Keys[KLEFT] )
		{
			m_vel = 0;
		}
		
		if ( m_vel )
		{
			m_x += m_vel;
			
			if ( m_x < 14 + PLAYER_W/2 )
				m_x = 14 + PLAYER_W/2;
			
			if ( m_x > SCREEN_W - 14 - PLAYER_W/2 )
				m_x = SCREEN_W - 14 - PLAYER_W/2;
		}

		bool didShoot = false;

		int shoot_speed = (m_parent->getGameRules() & GR_FAST_SHOOTING)?MISSILE_FAST_SPEED:MISSILE_SHOOT_SPEED; 
		
		if ( m_lastShoot + shoot_speed < SDL_GetTicks() )
		{
			if (m_parent->getGameRules() & GR_PRIMESHOOTER)
			{
				if ( g_Keys[KSHOOT] )
				{
					m_lastShoot = SDL_GetTicks();
					Missile *new_missile = new Missile(m_parent, m_x, m_y-32, 8, 90.0, 0);
					m_missiles.push_back(new_missile);
					didShoot = true;
				}
				else
				{
					int shot = 0;
					for ( int i=K0; i<=KR; ++i )
					{
						if ( g_Keys[i] ) 
						{
							shot = m_parent->translateKeyPress(i);
							break;
						}
					}
					
					if ( shot != 0 )
					{
						m_lastShoot = SDL_GetTicks();
						Missile *new_missile = new Missile(m_parent, m_x, m_y-32, 8, 90.0, shot);
						m_missiles.push_back(new_missile);
						didShoot = true;
					}
				}
			}
			else if (m_parent->getGameRules() & GR_COLORSHOOTER)
			{
			// FIXME: tsk tsk... there aren't aliens with more than 1 color... so...
			// hmm... color shooting should work just like prime shooting, key -> missile
			// most people have a hard time clicking a mouse, if we make them press two keys at once...
//				if ( g_Keys[KSHOOT] )
				{
					int color = 0;
					for ( int i=K0; i<=KR; ++i )
						if ( g_Keys[i] ) color = m_parent->translateKeyPress(i);
					
					if ( color != 0 )
					{
						m_lastShoot = SDL_GetTicks();
						Missile *new_missile = new Missile(m_parent, m_x, m_y-32, 8, 90.0, color);
						m_missiles.push_back(new_missile);
						didShoot = true;
					}
				}
			}
			else
			{
				if ( g_Keys[KSHOOT] )
				{
					m_lastShoot = SDL_GetTicks();
					Missile *new_missile = new Missile(m_parent, m_x, m_y-16, 8, 90.0);
					m_missiles.push_back(new_missile);
					didShoot = true;
				}
			}
		}

		if ( didShoot )
		{
		    Mix_PlayChannel( -1, g_Sounds[SOUND_SHOOT], 0 );
			for ( int i=0; i<4; ++i )
			{
				m_parent->newSprite( SPRITE_SMOKE, m_x - 4 + i*2, m_y - 60 );
			}
		}
		
		int x, y;
		
		for ( int i=0; i<(int)m_missiles.size(); ++i )
		{
			m_missiles[i]->tick();
			if ( m_missiles[i]->colCheck() )
			{
				m_missiles[i]->getExplosionCoords( x, y );
				m_parent->newSprite( SPRITE_EXPLOSION, x, y );
				delete m_missiles[i];
				m_missiles.erase(m_missiles.begin()+i);
				--i;
			}
		}
	}
	else
	{
		if ( m_deathFXTimer.get_ticks() > rand()%250 + 500 )
		{
			SDL_Rect ab;
			getBounds( &ab );
			m_parent->newSprite( SPRITE_EXPLOSION, ab.x + rand()%ab.w, ab.y + rand()%ab.h );
			Mix_PlayChannel( -1, g_Sounds[SOUND_PLAYERDEAD], 0 );
			
			m_deathFXTimer.start();
		}
	}
	
	this->render();
}
